﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
using log4net;
using log4net.Util;
using MaterialDesignThemes.Wpf;
using Lhn.Ds.Core.CarDevice;
using Lhn.Ds.Core.Exceptions;
using Lhn.Ds.Core.Service;

namespace Lhn.Ds.Core
{
    /**
     * 程序上下文
     * 系统的action以"//[消息类型]]"开头，组件的以"/[组件名称]/[消息类型][/[附加动作]]"开头
     */
    public class DsContext
    {
        public Client Client { get; set; }=new Client();
        public static readonly DsContext InstanceData = new DsContext();
        public static readonly XKReader XkReader=new XKReader();

        public static readonly ILog Log =
            LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        //消息订阅记录表
        private Hashtable _registers = new Hashtable();

        public CompositionContainer IOC { get; private set; }

        public SnackbarMessageQueue SnackbarMessageQueue { get; set; }

        public void InitContainer()
        {
            var catalog = new AggregateCatalog(new DirectoryCatalog("."),
                new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            IOC = new CompositionContainer(catalog);
            IOC.ComposeParts(this);
        }

        /**
         * 向系统注册action，注册自己要订阅的信息
         */
        public void SubscribeAction(string type, IControl control)
        {
            if (type == null)
            {
                Log.Debug($"控件:{GetTypeName(control)},注册的类型null,trace:{GetInvokeInfo()}");
                return;
            }

            if (control == null)
            {
                Log.Debug($"要注册的类型${type}的控件为空,tracke:{GetInvokeInfo()}");
                return;
            }

            if (!(_registers[type] is List<IControl> list))
            {
                list = new List<IControl>();
                _registers[type] = list;
            }

            list.Add(control);
        }

        /**
         * 发布action
         */
        public void DispatchAction(string type, object param)
        {
            DispatchAction(type, param, null);
        }

        public void DispatchAction(string type)
        {
            DispatchAction(type, null, null);
        }

        /**
         * 发布action
         */
        public void DispatchAction(string type, object param, Action callback)
        {
            Task.Factory.StartNew(() =>
            {
                if ((_registers[type] is List<IControl> list))
                {
                    foreach (var control in list)
                    {
                        try
                        {
                            control.OnAction(type, param);
                        }
                        catch (System.Exception e)
                        {
                            Log.Debug($"发布Action,Type={type},在触发Controlle{control.GetType().FullName}时发生错误,{e.Message}",
                                e);
                        }
                    }

                    callback?.Invoke();
                }
            });
        }
        public bool ProccessException(System.Exception e)
        {
            var eee = e;
            if (eee.InnerException != null) eee = e.InnerException;
            if (e is SytechException)
            {
                eee = e;
            }
            if (eee is SytechException)
            {
                //通知ui线程做回应
                var ee = eee as SytechException;
                Log.Error($"{ee.Message},Info:[{ee.SytechMessage}]", ee);
                DsContext.InstanceData.SnackbarMessageQueue.Enqueue(ee.Message);
                return true;
            }
            Log.Error($"致命错误：{eee.Message}", eee);
            if (e is System.ArithmeticException||eee is ArithmeticException)
            {
                return true;
            }
            return false;
        }
        private string GetInvokeInfo()
        {
            var frame = (new StackTrace()).GetFrame(2);
            return frame.ToString();
        }

        private string GetTypeName(object obj)
        {
            if (obj == null)
            {
                return "null";
            }

            return obj.GetType().FullName;
        }
    }
}